package com.mrzhou.nio;

import org.omg.PortableInterceptor.SYSTEM_EXCEPTION;

import java.io.IOException;
import java.math.BigDecimal;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;

/**
 *  java NIO 服务器
 */
public class NioServer {

    private int port; // 服务器端口
    private Selector selector; // NIO 选择器
    private ExecutorService service = Executors.newFixedThreadPool(5); // 线程池

    public static void main(String[] args) {
        NioClient nioClient = null;

        Map<Long, String> map = new HashMap<>();
        map.put(1000000000000000L, null);
        map.put(1000000000000001L, "23556");

        Optional.ofNullable(nioClient).ifPresent(var -> System.out.println(var)); // .filter(var -> var == true).ifPresent(var -> System.out.println("最后执行"));

        System.out.println(new BigDecimal("-0.000000000001").toPlainString());

        BigDecimal source = new BigDecimal("999.999999");
        BigDecimal target = new BigDecimal("999.999999");
        System.out.println(source.equals(target));

//        List<String> list = new ArrayList<>();
//        list.add("A"); list.add("B"); list.add("C"); list.add("D");
//        AtomicInteger item = new AtomicInteger(1);
//        list.stream().forEach(var -> System.out.println(String.format("%s:%s", var, item.getAndIncrement())));

//        new NioServer(8888).start();
    }

    public static boolean handler() {
        System.out.println("中间执行");
        return true;
    }

    public NioServer(int port) {
        this.port = port;
    }

    public void init() {
        ServerSocketChannel ssc;
        try {
            ssc = ServerSocketChannel.open(); // 打开服务信道
            ssc.configureBlocking(false);
            ssc.bind(new InetSocketAddress("10.130.2.165", port)); // 将信道绑定到本地地址, 同时配置scoket监听连接
            selector = Selector.open(); //
            ssc.register(selector, SelectionKey.OP_ACCEPT); // 将信道注册到对应的选择器中
            System.out.println("NIO Server 准备完成！！！");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     *
     */
    public void accept(SelectionKey key) {
        try {
            ServerSocketChannel ssc = (ServerSocketChannel) key.channel(); // 获取Selector中获取Channel
            SocketChannel sc = ssc.accept(); // 监听信到是否收到消息
            sc.configureBlocking(false);
            ssc.register(selector, SelectionKey.OP_ACCEPT);
            System.out.println("accept 监听的 client: " + sc.socket().getInetAddress().getHostName());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void start() {
        this.init(); // 初始化NIO服务器
        while(true) { // 无限循环, 使服务一直开启
            try{
                int events = selector.select(); // 当前选择器中的Channel中有多少可用的IO操作
                if(events > 0) {
                    Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                    while (iterator.hasNext()) {
                        SelectionKey key = iterator.next();
                        iterator.remove();
                        if(key.isAcceptable()) { // 当前Channel是否准备接受新的socket
                            this.accept(key);
                        } else {
                            new NioServerHandler(key).run();
//                            service.submit();  // 将任务提交到线程池中处理
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static class NioServerHandler implements Runnable {

        private SelectionKey selectionKey;

        public NioServerHandler(SelectionKey selectionKey) {
            this.selectionKey = selectionKey;
        }

        @Override
        public void run() {
            try{
                if (selectionKey.isReadable()) { // 当前选择器信道是否可读
                    SocketChannel channel = (SocketChannel) selectionKey.channel();
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    channel.read(buffer);
                    buffer.flip();
                    System.out.println(java.lang.String.format("收到客户端: %s的数据%s" , channel.socket().getInetAddress().getHostName(), new String(buffer.array())));

                    String msg = String.format("%s【Hello Client】", channel.socket().getInetAddress().getHostName());
                    ByteBuffer outBuffer = ByteBuffer.wrap(msg.getBytes());
                    channel.write(outBuffer);
                    selectionKey.cancel(); // 重选择其中取消当前信道
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}
